﻿using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Loong.Domain.Entities;

namespace Loong.Dapper.DbAccessors
{
    public interface IDapperDbAccessor<TEntity, TPrimaryKey> : IDapperDbAccessor where TEntity : class, IEntity<TPrimaryKey>
    {
        [NotNull]
        TEntity Single([NotNull] TPrimaryKey id);

        [NotNull]
        TEntity Single(Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        Task<TEntity> SingleAsync([NotNull] TPrimaryKey id);

        [NotNull]
        Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        TEntity Get([NotNull] TPrimaryKey id);

        [NotNull]
        Task<TEntity> GetAsync([NotNull] TPrimaryKey id);

        [CanBeNull]
        TEntity FirstOrDefault([NotNull] TPrimaryKey id);

        [CanBeNull]
        TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate);

        [CanBeNull]
        Task<TEntity> FirstOrDefaultAsync([NotNull] TPrimaryKey id);

        [CanBeNull]
        Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        IEnumerable<TEntity> GetAll();

        [NotNull]
        IEnumerable<TEntity> GetAll([NotNull] Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        Task<IEnumerable<TEntity>> GetAllAsync();

        [NotNull]
        Task<IEnumerable<TEntity>> GetAllAsync([NotNull] Expression<Func<TEntity, bool>> predicate);

        long Count([NotNull] Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        Task<long> CountAsync([NotNull] Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        IEnumerable<TEntity> Query([NotNull] string query, [CanBeNull] object parameters = null);

        [NotNull]
        IEnumerable<TAny> Query<TAny>([NotNull] string query, [CanBeNull] object parameters = null) where TAny : class;

        [NotNull]
        Task<IEnumerable<TEntity>> QueryAsync([NotNull] string query, [CanBeNull] object parameters = null);

        [NotNull]
        Task<IEnumerable<TAny>> QueryAsync<TAny>([NotNull] string query, [CanBeNull] object parameters = null) where TAny : class;

        int Execute([NotNull] string query, [CanBeNull] object parameters = null);

        Task<int> ExecuteAsync([NotNull] string query, [CanBeNull] object parameters = null);

        void Insert([NotNull] TEntity entity);

        [NotNull]
        Task InsertAsync([NotNull] TEntity entity);

        TPrimaryKey InsertAndGetId([NotNull] TEntity entity);

        [NotNull]
        Task<TPrimaryKey> InsertAndGetIdAsync([NotNull] TEntity entity);

        void Update([NotNull] TEntity entity);

        [NotNull]
        Task UpdateAsync([NotNull] TEntity entity);

        void Delete([NotNull] TEntity entity);

        void Delete([NotNull] Expression<Func<TEntity, bool>> predicate);

        [NotNull]
        Task DeleteAsync([NotNull] TEntity entity);

        [NotNull]
        Task DeleteAsync([NotNull] Expression<Func<TEntity, bool>> predicate);
    }
}
